// Copyright (C) 2022 即时通讯网(52im.net) & Jack Jiang.
// The RainbowChat Project. All rights reserved.
//
// 【本产品为著作权产品，合法授权后请放心使用，禁止外传！】
// 【本次授权给：<广西木子科技有限公司>，授权编号：<NT220402151538>，代码指纹：<A.648883738.885>，技术对接人微信：<ID: Lingmuziyi>】
// 【授权寄送：<收件：李先生、地址：南宁市科园西十路11号国电智能大厦1101F、电话：17736659550、邮箱：yingshashou@vip.qq.com>】
//
// 【本系列产品在国家版权局的著作权登记信息如下】：
// 1）国家版权局登记名(简称)和权证号：RainbowChat    （证书号：软著登字第1220494号、登记号：2016SR041877）
// 2）国家版权局登记名(简称)和权证号：RainbowChat-Web（证书号：软著登字第3743440号、登记号：2019SR0322683）
// 3）国家版权局登记名(简称)和权证号：RainbowAV      （证书号：软著登字第2262004号、登记号：2017SR676720）
// 4）国家版权局登记名(简称)和权证号：MobileIMSDK-Web（证书号：软著登字第2262073号、登记号：2017SR676789）
// 5）国家版权局登记名(简称)和权证号：MobileIMSDK    （证书号：软著登字第1220581号、登记号：2016SR041964）
// * 著作权所有人：江顺/苏州网际时代信息科技有限公司
//
// 【违法或违规使用投诉和举报方式】：
// 联系邮件：jack.jiang@52im.net
// 联系微信：hellojackjiang
// 联系QQ号：413980957
// 授权说明：http://www.52im.net/thread-1115-1-1.html
// 官方社区：http://www.52im.net
package com.x52im.rainbowchat.http.util;

import java.security.GeneralSecurityException;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Properties;
import java.util.Vector;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.Address;
import javax.mail.AuthenticationFailedException;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;

import com.eva.framework.utils.LoggerFactory;
import com.sun.mail.util.MailSSLSocketFactory;

/**
 * 要发出的邮件元数据对象（一封邮件一个实例）.
 * <p>
 * 20170921日Jack Jiang 增加了SSL的支持。
 *
 * @author Jack Jiang(http://www.52im.net/space-uid-1.html)
 */
public class OutgoingMail {
    //定义发件人、收件人、SMTP服务器、用户名、密码、主题、内容等
    private String displayName;
    private String to;
    private String from;
    private String smtpServer;
    /**
     * SMTP服务器端口（默认是不支持SSL的普通SMTP端口25）
     */
    private String smtpPort = "25";
    private String username;
    private String password;
    private String subject;
    private String content;
    /**
     * 服务器是否要身份认证（默认true）
     */
    private boolean ifAuth = true;
    /**
     * 服务器是否需要SSL（默认false）
     */
    private boolean supportSSL = false;

    /**
     * 用于保存发送附件的文件名的集合
     */
    private Vector file = new Vector();
    /**
     * 是否支持BUBUG信息输出
     */
    private boolean canDebug = false;

    public OutgoingMail() {
    }

    /**
     * 初始化SMTP服务器地址、发送者E-mail地址、用户名、密码、接收者、主题、内容。
     *
     * @param smtpServer   发件SMTP主机域名
     * @param from         发件人邮件地址
     * @param displayNamev 发件人姓名（非必须）
     * @param username     发件人邮箱用户名（就是@符号前面那串）
     * @param password     发件人邮箱明文密码
     * @param to           收件人邮件地址
     * @param subject      邮件主题
     * @param content      邮件内容
     * @param smtpPort     SMTP服务端端口，如果本参数为空，则自动使用默认的25端口
     * @param supportSSL   是否需要使用SSL支持，现在越来越多的邮件服务商不提供非SSL方式了，如需支持请设为true
     */
    public OutgoingMail(String smtpServer, String from, String displayName
            , String username, String password, String to, String subject
            , String content, String smtpPort, boolean supportSSL) {
        this.smtpServer = smtpServer;
        this.from = from;
        this.displayName = displayName;
        this.ifAuth = true;
        this.username = username;
        this.password = password;
        this.to = to;
        this.subject = subject;
        this.content = content;

        this.smtpPort = smtpPort;
        this.supportSSL = supportSSL;
    }

//	/**
//	 * 初始化SMTP服务器地址、发送者E-mail地址、接收者、主题、内容
//	 */
//	public OutgoingMail(String smtpServer, String from, String displayName,
//			String to, String subject, String content)
//	{
//		this.smtpServer = smtpServer;
//		this.from = from;
//		this.displayName = displayName;
//		this.ifAuth = false;
//		this.to = to;
//		this.subject = subject;
//		this.content = content;
//	}

    /**
     * 发送邮件
     */
    public HashMap send() throws Exception {
        HashMap map = new HashMap();
        map.put("state", "success");
        String message = "邮件发送成功！";
        Session session = null;

        Properties props = System.getProperties();
        // SMTP服务器
        props.put("mail.smtp.host", smtpServer);
        // 端口
        props.setProperty("mail.smtp.port", (smtpPort == null || smtpPort.length() == 0) ? "25" : smtpPort);

        // 如果需要支持SSL
        if (this.supportSSL) {
            // 使用SSL企业邮箱必需： 开启SSL安全协议
            MailSSLSocketFactory sf = null;
            try {
                sf = new MailSSLSocketFactory();
                sf.setTrustAllHosts(true);
            } catch (GeneralSecurityException e1) {
                e1.printStackTrace();
            }
            props.put("mail.smtp.ssl.enable", "true");
            props.put("mail.smtp.ssl.socketFactory", sf);
        }

        // 发件SMTP服务器需要发件人的身份认证
        if (ifAuth) {
            props.put("mail.smtp.auth", "true");
            SmtpAuthImpl smtpAuth = new SmtpAuthImpl(username, password);
            session = Session.getDefaultInstance(props, smtpAuth);
        } else {
            props.put("mail.smtp.auth", "false");
            session = Session.getDefaultInstance(props, null);
        }
        session.setDebug(canDebug);
        Transport trans = null;
        try {
            Message msg = new MimeMessage(session);
            try {
                Address from_address = new InternetAddress(from, displayName);
                msg.setFrom(from_address);
            } catch (java.io.UnsupportedEncodingException e) {
                e.printStackTrace();
                throw e;
            }
            InternetAddress[] address = {new InternetAddress(to)};
            msg.setRecipients(Message.RecipientType.TO, address);
            msg.setSubject(subject);//.setSubject(subject);
            Multipart mp = new MimeMultipart();
            MimeBodyPart mbp = new MimeBodyPart();
            mbp.setContent(content.toString(), "text/html;charset=UTF-8");
            mp.addBodyPart(mbp);
            if (!file.isEmpty()) {//有附件
                Enumeration efile = file.elements();
                while (efile.hasMoreElements()) {
                    mbp = new MimeBodyPart();

                    String filePath = "", filename = "";
                    Object of = efile.nextElement();

                    //文件名是否使用与路径不一样的文件名（别名）
                    boolean useDiffName = false;
                    //本对象的出现就是为了使用别名
                    if (of instanceof Attachfile) {
                        filePath = ((Attachfile) of).getFilePath();
                        filename = ((Attachfile) of).getFileName();
                        useDiffName = true;
                    } else if (of instanceof String) {
                        //不使用别名
                        filePath = of.toString();
                    } else {
//						System.out.println("未知附件文件信息对象！"+of);
                        LoggerFactory.getLog().debug("【邮件数据准备中】smtp=" + smtpServer + ",port=" + smtpPort
                                + ",uname=" + username + ",psw=" + password + "(SSL? " + this.supportSSL + "), message="
                                + "未知附件文件信息对象！" + of);
                    }

                    //得到数据源
                    FileDataSource fds = new FileDataSource(filePath);
                    //得到附件本身并至入BodyPart
                    mbp.setDataHandler(new DataHandler(fds));
                    //得到文件名同样至入BodyPart(记得将文件名MimeUtility.encodeText，否则就等着乱码吧，
                    //其实就是转换成BASE64编码再加上首尾的个别附加字符而已）
                    mbp.setFileName(MimeUtility.encodeText(useDiffName ? filename : fds.getName()));
                    mp.addBodyPart(mbp);
                }
                file.removeAllElements();
            }
            msg.setContent(mp); //Multipart加入到信件
            msg.setSentDate(new Date()); //设置信件头的发送日期
            //发送信件
            msg.saveChanges();
            trans = session.getTransport("smtp");
            LoggerFactory.getLog().debug("【正在发送邮件】smtp=" + smtpServer + ",port=" + smtpPort
                    + ",uname=" + username + ",psw=" + password + "(SSL? " + this.supportSSL + ")");
            trans.connect(smtpServer, username, password);
            trans.sendMessage(msg, msg.getAllRecipients());
            trans.close();

        } catch (AuthenticationFailedException e) {
            map.put("state", "failed");
            message = "邮件发送失败！错误原因：\n" + "身份验证错误!";
//			e.printStackTrace();
            LoggerFactory.getLog().debug("【邮件发送失败】smtp=" + smtpServer + ",port=" + smtpPort
                    + ",uname=" + username + ",psw=" + password + "(SSL? " + this.supportSSL + "), message=" + message, e);
            throw e;
        } catch (MessagingException e) {
            message = "邮件发送失败！错误原因：\n" + e.getMessage();
            map.put("state", "failed");
//			e.printStackTrace();
            LoggerFactory.getLog().debug("【邮件发送失败】smtp=" + smtpServer + ",port=" + smtpPort
                    + ",uname=" + username + ",psw=" + password + "(SSL? " + this.supportSSL + "), message=" + message, e);
            Exception ex = null;
            if ((ex = e.getNextException()) != null) {
//				System.out.println(ex.toString());
//				ex.printStackTrace();
                LoggerFactory.getLog().debug(ex.toString(), ex);
            }

            throw e;
        }
        //System.out.println("\n提示信息:"+message);
        map.put("message", message);
        return map;
    }

    /**
     * 设置SMTP服务器地址
     */
    public void setSmtpServer(String smtpServer) {
        this.smtpServer = smtpServer;
    }

    /**
     * 设置发件人的地址
     */
    public void setFrom(String from) {
        this.from = from;
    }

    /**
     * 设置显示的名称
     */
    public void setDisplayName(String displayName) {
        this.displayName = displayName;
    }

    /**
     * 设置服务器是否需要身份认证
     */
    public void setIfAuth(boolean ifAuth) {
        this.ifAuth = ifAuth;
    }

    /**
     * 设置E-mail用户名
     */
    public void setUserName(String username) {
        this.username = username;
    }

    /**
     * 设置E-mail密码
     */
    public void setPassword(String password) {
        this.password = password;
    }

    /**
     * 设置接收者
     */
    public void setTo(String to) {
        this.to = to;
    }

    /**
     * 设置主题
     */
    public void setSubject(String subject) {
        this.subject = subject;
    }

    /**
     * 设置主体内容
     */
    public void setContent(String content) {
        this.content = content;
    }

    /**
     * 该方法用于收集附件名
     */
    public void addAttachfile(String fname) {
        file.addElement(fname);
    }

    /**
     * 该方法用于收集附件
     */
    public void addAttachfile(Attachfile fname) {
        file.addElement(fname);
    }

    public boolean isCanDebug() {
        return canDebug;
    }

    public void setCanDebug(boolean canDebug) {
        this.canDebug = canDebug;
    }

    /**
     * 存放附件文件基信息的内部类.
     */
    public static class Attachfile {
        private String filePath, fileName;

        public Attachfile(String filePath, String fileName) {
            this.filePath = filePath;
            this.fileName = fileName;
        }

        public String getFilePath() {
            return filePath;
        }

        public void setFilePath(String filePath) {
            this.filePath = filePath;
        }

        public String getFileName() {
            return fileName;
        }

        public void setFileName(String fileName) {
            this.fileName = fileName;
        }
    }

    /**
     * SMTP认证对象.
     */
    public class SmtpAuthImpl extends Authenticator {
        private String username, password;

        public SmtpAuthImpl(String username, String password) {
            this.username = username;
            this.password = password;
        }

        protected PasswordAuthentication getPasswordAuthentication() {
            return new PasswordAuthentication(username, password);
        }
    }

    public static void main(String args[]) throws Exception {
//		// 发送网易邮件：使用非SSL方式，测试成功！
////		OutgoingMail om = new OutgoingMail("smtp.163.com", "jb2011@163.com", "MissU Master",
////				"jb2011","????????????????",
//////				"js4713@163.com",
////				"413980957@qq.com",
////				"邀请你使用MissU", "邀请你使用MissU邀请你使用MissU邀请你使用MissU邀请你使用MissU邀请你使用MissU."
////				, "25", false);
//
//		// 发送QQ邮件：使用SSL方式，测试成功！
////		OutgoingMail om = new OutgoingMail("smtp.qq.com"
////				, "249751626@qq.com"
////				, "XXMissU Master"
////				, "249751626"
////				,"????????????????????",
////				"413980957@qq.com",
////				"XX邀请你使用MissU"
////				, "XX邀请你使用MissU邀请你使用MissU邀请你使用MissU邀请你使用MissU邀请你使用MissU."
////				, "465", true);
//
//		// 发送新浪邮件：使用非SSL方式，测试成功！
//		OutgoingMail om = new OutgoingMail("smtp.sina.com", "hellojackjiang@sina.com", "SSAAMissU Master",
//				"hellojackjiang","??????????",
////				"js4713@163.com",
//				"413980957@qq.com",
//				"SSAA邀请你使用MissU"
//				, "SSAA邀请你使用MissU邀请你使用MissU邀请你使用MissU邀请你使用MissU邀请你使用MissU."
//				, "25", false);
//
////		om.addAttachfile("C:\\js4713.txt");
////		om.addAttachfile("C:\\Data1.cab");
////		om.addAttachfile("d:\\复件1147.bmp");
////		om.addAttachfile("d:\\最令人感动的谎言（伟大的母爱）.doc");
////		om.addAttachfile(new Attachfile("d:\\复件jad.exe","jad_别名.exe"));
//
//		HashMap hm = om.send();
//		if(hm.get("message")!=null)//发送成功了
//		{
//			System.out.println(hm.get("message"));
//		}
//		else
//		{
//			System.out.println(hm.get("state"));
//		}
    }
}
